Skip to content

Harden databento ingest: progress/timing, durable + reconcilable manifest, windowed n.1 stats#40

Open
mspinola wants to merge 3 commits into
mainfrom
databento-ingest-hardening
Open

Harden databento ingest: progress/timing, durable + reconcilable manifest, windowed n.1 stats#40
mspinola wants to merge 3 commits into
mainfrom
databento-ingest-hardening

Conversation

@mspinola

Copy link
Copy Markdown
Owner

Operational hardening for the databento ingest, driven by a ~24-hour backfill run. All on top of the merged two-stage producer.

Progress + timing

Per-symbol [i/N] with run-elapsed, and per-fetch duration — which makes the statistics schema visibly the bottleneck (millions of rows) vs ohlcv-1d (seconds).

Durable manifest

The ingest manifest is now persisted after every fetch instead of only at the end, so an interrupted run resumes where it left off instead of re-downloading. Plus reconcile_manifest() / cotdata-update --reconcile-databento to rebuild the manifest from the raw parquets already on disk (recovery for a run that predates the durable write; reads local files only, no API).

Resume bug fix (422)

databento's time range is half-open (start < end), so an already-current symbol computed start == end and 422'd (data_time_range_start_on_or_after_end), falsely counting as a failure. That would make every steady-state (nothing-new) run exit non-zero — e.g. the nightly cron false-alarming. Guard changed from > to >=.

Windowed n.1 statistics (--windowed-n1-stats [DAYS], default 3)

n.1 settlement is only needed at roll dates, so fetch the n.1 statistics schema only in ±DAYS windows around each roll (found from the on-disk n.0 instrument_id) instead of full history.

Validated on already-downloaded data — roll gaps are identical to the full pull, at a fraction of the download:

sym n.1 stats rows: full → windowed saving
ES 1.42M → 154K 89%
NQ 1.93M → 273K 86%
GC 722K → 128K 82%
SI 530K → 71K 87%
CL 1.09M → 357K 67%

Since n.1 statistics is ~30–45% of the total, that's ~30–35% off total runtime with no back-adjustment accuracy loss. The full n.0 statistics (daily settlement + OI) and n.1 ohlcv are unchanged. A watermark advances the resume point only through the last contiguous successful window, so a transient failure is retried rather than silently leaving a roll's gap unmeasured. Trades bytes for call count (one small n.1 query per roll).

113 tests green (incl. a full-vs-windowed identical-back-adjustment test, a start == end regression, and a manifest-reconcile test).

🤖 Generated with Claude Code

mspinola and others added 3 commits July 24, 2026 21:13
…fest, windowed n.1 stats

Operational hardening for the databento ingest, driven by a ~24h backfill.

- Progress + timing: per-symbol [i/N] with run-elapsed, and per-fetch duration (reveals the statistics schema as the bottleneck).
- Durable manifest: persisted after EVERY fetch instead of only at the end, so an interrupted run resumes instead of re-downloading.
- reconcile_manifest() + 'cotdata-update --reconcile-databento': rebuild the manifest from the raw parquets on disk (recovery for runs that predate the durable write). No API.
- Resume bug fix: skip when start >= end. databento requires start < end, so an already-current symbol 422'd (data_time_range_start_on_or_after_end) and falsely reported failure — which would make every steady-state run exit non-zero.
- 'cotdata-update --windowed-n1-stats [DAYS]' (default 3): fetch the n.1 statistics schema only in windows around roll dates (settlement is only needed at rolls). Validated on downloaded data: roll gaps IDENTICAL to the full pull, 67-89% fewer n.1 rows (~30-35% off total runtime), zero accuracy loss. Watermark resume retries transient window failures rather than silently dropping a roll's gap.

113 tests green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The historical streaming API (timeseries.get_range) throws read timeouts, aborted connections, and 'Response ended prematurely' often on large from-inception pulls. _fetch now retries 3x with linear backoff so these self-heal within the run instead of dropping the fetch (which loses a symbol/roll-window until the next re-run).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Streaming timeseries.get_range times out on from-inception statistics (read timeouts, dropped streams). ingest_batch() submits one databento BATCH job per (feed, schema) covering all symbols still needing it, waits, downloads the CSV files, and parses them into the SAME raw store + manifest — so build() and reconcile() are unchanged. Statistics are fetched full (batch handles the volume; no windowing needed). Routed via 'cotdata-update --ingest-databento --batch'.

The CSV parsing follows the proven dormant run_batch_backfill pattern (groupby symbol, instrument_id for rolls).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant